/*
一致性哈希算法
*/
package hash

import (
	"hash/crc32"
	"log"
	"math"
	"sort"
	"strconv"
	"sync"
)

// Hash 函数类型
type Hash func(data []byte) uint32

// 默认使用crc32算法
var curHash Hash = crc32.ChecksumIEEE

// 默认虚拟节点数
var defaultVirtualNode int = 3

// ConsitentMap 使用map存储所有节点信息
type ConsitentMap struct {
	Keys         []int          // 存储节点信息（map的key）
	NodeMap      map[int]string // 存储整体哈希值
	sync.RWMutex                // 读写锁
}

// 新建hash
func New() *ConsitentMap {
	m := &ConsitentMap{
		Keys:    make([]int, 0),
		NodeMap: make(map[int]string),
	}
	// 定时任务
	m.TimeWork()
	return m
}

// 添加新的节点
func (m *ConsitentMap) Add(virtualNode int, addrs []string) {
	m.Lock()
	defer m.Unlock()
	if virtualNode < 0 || virtualNode >= math.MaxInt32 { // 虚拟节点数目错误
		virtualNode = defaultVirtualNode
	}
	for _, addr := range addrs {
		for i := 0; i < virtualNode; i++ { // 部署虚拟节点
			hash := int(curHash([]byte(strconv.Itoa(i) + addr)))
			m.Keys = append(m.Keys, hash)
			m.NodeMap[hash] = addr
		}
	}
	sort.Ints(m.Keys)
}

// 获取当前最接近的节点
func (m *ConsitentMap) Get(key string) string {
	m.RLock()
	defer m.RUnlock()
	if len(m.Keys) == 0 { // 不符合条件
		return ""
	}
	//
	hash := int(curHash([]byte(key)))
	// 二分查找最近的节点
	idx := sort.Search(len(m.Keys), func(i int) bool {
		return m.Keys[i] >= hash
	})
	idx = idx % len(m.Keys)
	// 返回地址
	return m.NodeMap[m.Keys[idx]]
}

// 获取当前最接近的节点
func (m *ConsitentMap) Del(hash int) {
	m.Lock()
	defer m.Unlock()
	defer func() {
		err := recover()
		if err != nil {
			log.Println("[LOG_Del] runtime error: ", err)
		}
	}()

	if len(m.Keys) == 0 { // 不符合条件
		return
	}

	url := m.NodeMap[hash]
	if url == "" { // 不存在该节点
		return
	}
	// 查找节点
	idx := sort.Search(len(m.Keys), func(i int) bool {
		return m.Keys[i] >= hash
	})
	// 删除该节点
	m.Keys = append(m.Keys[:idx], m.Keys[idx+1:]...)
	delete(m.NodeMap, hash)
}
